<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>循环链表图片浏览器</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
            color: white;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 2rem;
            overflow-x: hidden;
        }
        
        .container {
            max-width: 1400px;
            width: 100%;
            text-align: center;
        }
        
        h1 {
            font-size: 2.5rem;
            margin-bottom: 1rem;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
        }
        
        .description {
            font-size: 1.1rem;
            margin-bottom: 2rem;
            max-width: 800px;
            margin-left: auto;
            margin-right: auto;
            line-height: 1.6;
        }
        
        .file-input-section {
            background: rgba(255, 255, 255, 0.1);
            padding: 20px;
            border-radius: 15px;
            margin-bottom: 20px;
            width: 100%;
            max-width: 600px;
        }
        
        .file-input-label {
            display: block;
            margin-bottom: 15px;
            font-size: 1.1rem;
            font-weight: 600;
        }
        
        .file-input {
            width: 100%;
            padding: 12px;
            border: 2px dashed rgba(255, 255, 255, 0.3);
            border-radius: 10px;
            background: rgba(255, 255, 255, 0.1);
            color: white;
            margin-bottom: 15px;
        }
        
        .load-btn {
            background: linear-gradient(45deg, #4ecdc4, #44a08d);
            border: none;
            padding: 12px 24px;
            border-radius: 25px;
            color: white;
            font-size: 1rem;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
        }
        
        .load-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
        }
        
        .load-btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
            transform: none;
        }
        
        .image-list {
            margin-top: 15px;
            text-align: left;
            max-height: 200px;
            overflow-y: auto;
        }
        
        .image-item {
            padding: 8px;
            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
            font-size: 0.9rem;
        }
        
        .viewer-container {
            position: relative;
            width: 100%;
            height: 500px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-bottom: 30px;
            overflow: visible;
        }
        
        .image-track {
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
            height: 100%;
            width: 100%;
        }
        
        .image-node {
            position: absolute;
            width: 400px;
            height: 300px;
            transition: all 0.5s ease;
            border-radius: 15px;
            overflow: hidden;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
            cursor: grab;
        }
        
        .image-node.active {
            z-index: 10;
            transform: scale(1.1);
            width: 500px;
            height: 375px;
        }
        
        .image-node.left {
            transform: translateX(-120%) scale(0.9);
            opacity: 0.8;
            z-index: 5;
        }
        
        .image-node.right {
            transform: translateX(120%) scale(0.9);
            opacity: 0.8;
            z-index: 5;
        }
        
        .image-node.far-left {
            transform: translateX(-200%) scale(0.7);
            opacity: 0.4;
            z-index: 1;
        }
        
        .image-node.far-right {
            transform: translateX(200%) scale(0.7);
            opacity: 0.4;
            z-index: 1;
        }
        
        .image-node img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
        }
        
        .image-title {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            background: linear-gradient(transparent, rgba(0,0,0,0.8));
            color: white;
            padding: 20px 10px 10px;
            font-size: 1.2rem;
            font-weight: 600;
        }
        
        .nav-btn {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            background: rgba(255, 255, 255, 0.2);
            border: none;
            width: 60px;
            height: 60px;
            border-radius: 50%;
            font-size: 1.8rem;
            color: white;
            cursor: pointer;
            z-index: 20;
            backdrop-filter: blur(5px);
            transition: all 0.3s ease;
        }
        
        .nav-btn:hover {
            background: rgba(255, 255, 255, 0.3);
            transform: translateY(-50%) scale(1.1);
        }
        
        .prev {
            left: 50px;
        }
        
        .next {
            right: 50px;
        }
        
        .control-panel {
            display: flex;
            gap: 20px;
            justify-content: center;
            margin: 20px 0;
            flex-wrap: wrap;
        }
        
        .random-btn {
            background: linear-gradient(45deg, #ff6b6b, #ee5a24);
            border: none;
            padding: 15px 30px;
            border-radius: 50px;
            color: white;
            font-size: 1.1rem;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
        }
        
        .random-btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
        }
        
        .random-btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
            transform: none;
        }
        
        .linked-list-visual {
            display: flex;
            justify-content: center;
            align-items: center;
            margin: 30px 0;
            padding: 20px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 15px;
            flex-wrap: wrap;
            gap: 15px;
        }
        
        .list-node {
            display: flex;
            align-items: center;
            background: rgba(255, 255, 255, 0.2);
            padding: 12px 20px;
            border-radius: 25px;
            font-size: 1rem;
            transition: all 0.3s ease;
            min-width: 100px;
            justify-content: center;
        }
        
        .list-node.active {
            background: rgba(255, 255, 255, 0.4);
            box-shadow: 0 0 15px rgba(255, 255, 255, 0.5);
            transform: scale(1.1);
        }
        
        .list-node.animating {
            background: linear-gradient(45deg, #ff6b6b, #ee5a24);
            animation: pulse 0.5s ease infinite;
        }
        
        .arrow {
            font-size: 1.5rem;
            color: rgba(255, 255, 255, 0.7);
        }
        
        .loop-arrow {
            font-size: 1.8rem;
            color: rgba(255, 255, 255, 0.7);
            margin: 0 10px;
        }
        
        .status {
            margin: 20px 0;
            padding: 15px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 10px;
            font-size: 1.1rem;
        }
        
        .animation-info {
            background: rgba(255, 255, 255, 0.15);
            padding: 15px;
            border-radius: 10px;
            margin: 10px 0;
            animation: slideIn 0.5s ease;
        }
        
        .speed-meter {
            width: 100%;
            height: 20px;
            background: rgba(255, 255, 255, 0.2);
            border-radius: 10px;
            margin: 10px 0;
            overflow: hidden;
        }
        
        .speed-fill {
            height: 100%;
            background: linear-gradient(90deg, #4ecdc4, #44a08d);
            border-radius: 10px;
            transition: width 0.3s ease;
            width: 0%;
        }
        
        .instructions {
            margin-top: 30px;
            background: rgba(255, 255, 255, 0.1);
            padding: 20px;
            border-radius: 15px;
            max-width: 800px;
            text-align: left;
        }
        
        .instructions h3 {
            margin-bottom: 15px;
            text-align: center;
            font-size: 1.4rem;
        }
        
        .instructions ul {
            padding-left: 25px;
        }
        
        .instructions li {
            margin-bottom: 12px;
            line-height: 1.6;
            font-size: 1.1rem;
        }

        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.15); }
            100% { transform: scale(1); }
        }

        @keyframes slideIn {
            from {
                opacity: 0;
                transform: translateY(-20px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        @media (max-width: 768px) {
            .viewer-container {
                height: 400px;
            }
            
            .image-node {
                width: 300px;
                height: 225px;
            }
            
            .image-node.active {
                width: 350px;
                height: 262px;
            }
            
            .nav-btn {
                width: 50px;
                height: 50px;
                font-size: 1.5rem;
            }
            
            .prev {
                left: 20px;
            }
            
            .next {
                right: 20px;
            }
            
            h1 {
                font-size: 2rem;
            }
            
            .control-panel {
                gap: 10px;
            }
            
            .random-btn {
                padding: 12px 24px;
                font-size: 1rem;
            }
        }

        @media (max-width: 480px) {
            .image-node {
                width: 250px;
                height: 188px;
            }
            
            .image-node.active {
                width: 280px;
                height: 210px;
            }
            
            .viewer-container {
                height: 350px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>循环链表图片浏览器</h1>
        
		<p class="description">基于循环链表数据结构实现，自动读取images文件夹中的图片</p>
        
        <div class="file-input-section">
            <label class="file-input-label">选择图片文件（支持多选）:</label>
            <input type="file" id="fileInput" class="file-input" accept="image/*" multiple>
            <button class="load-btn" id="loadImages">加载图片</button>
            <div class="image-list" id="imageList"></div>
        </div>
        
        <div class="viewer-container">
            <button class="nav-btn prev">❮</button>
            <div class="image-track" id="imageTrack">
                <!-- 图片节点将通过JavaScript动态添加 -->
            </div>
            <button class="nav-btn next">❯</button>
        </div>
        
        <div class="control-panel">
            <button class="random-btn" id="randomSpin">随机轮动</button>
        </div>
        
        <div class="status">
            <p>当前图片: <span id="currentImage">-</span> | 链表长度: <span id="listLength">0</span></p>
            <p>当前节点指针: <span id="nodePointers">-</span></p>
            <div class="speed-meter">
                <div class="speed-fill" id="speedFill"></div>
            </div>
            <div id="animationInfo"></div>
        </div>
        
        <div class="linked-list-visual" id="linkedListVisual">
            <!-- 链表可视化将通过JavaScript动态添加 -->
        </div>
        
        <div class="instructions">
            <h3>使用说明</h3>
            <ul>
                <li>点击"选择图片文件"按钮，选择images文件夹中的所有图片</li>
                <li>图片文件名格式应为: image_{x}_{name}.jpg</li>
                <li>其中 {x} 为排序顺序，{name} 为图片标题</li>
                <li>点击"加载图片"按钮初始化浏览器</li>
                <li>使用左右箭头或拖动来浏览图片</li>
                <li>点击"随机轮动"进行带加速度的随机轮动</li>
				<li>带加速度的随机轮动，初始速度4图/秒，加速度4图/秒²，最大速度12图/秒，减速加速度-8图/秒²，终末速度3图/秒</li>
            </ul>
        </div>
    </div>

    <script>
        class ListNode {
            constructor(data, index) {
                this.data = data;
                this.index = index;
                this.next = null;
                this.prev = null;
                this.element = null;
            }
        }

        class CircularLinkedList {
            constructor() {
                this.head = null;
                this.current = null;
                this.length = 0;
            }
            
            append(data) {
                const newNode = new ListNode(data, this.length);
                
                if (!this.head) {
                    this.head = newNode;
                    newNode.next = newNode;
                    newNode.prev = newNode;
                    this.current = this.head;
                } else {
                    const tail = this.head.prev;
                    tail.next = newNode;
                    newNode.prev = tail;
                    newNode.next = this.head;
                    this.head.prev = newNode;
                }
                
                this.length++;
                return newNode;
            }
            
            next() {
                this.current = this.current.next;
                return this.current;
            }
            
            prev() {
                this.current = this.current.prev;
                return this.current;
            }
            
            getCurrent() {
                return this.current;
            }
            
            getAllNodes() {
                const nodes = [];
                let current = this.head;
                
                for (let i = 0; i < this.length; i++) {
                    nodes.push(current);
                    current = current.next;
                }
                
                return nodes;
            }
        }

        class CircularImageBrowser {
            constructor(container) {
                this.container = container;
                this.track = document.getElementById('imageTrack');
                this.list = new CircularLinkedList();
                this.nodeElements = new Map();
                this.isAnimating = false;
                
                // 速度参数
                this.initialSpeed = 4;    // 初始速度：4图/秒
                this.maxSpeed = 12;       // 最大速度：12图/秒
                this.acceleration = 4;    // 加速度：4图/秒²
                this.deceleration = -8;   // 减速度：-8图/秒²
                
                this.bindEvents();
            }
            
            // 从文件列表初始化
            initFromFiles(files) {
                const imageFiles = Array.from(files).filter(file => file.type.startsWith('image/'));
                
                if (imageFiles.length === 0) {
                    alert('请选择至少一张图片文件');
                    return;
                }
                
                // 解析文件名并排序
                const imageData = imageFiles.map(file => {
                    const fileName = file.name;
                    // 解析文件名格式: image_{x}_{name}.jpg
                    const match = fileName.match(/^image_(\d+)_(.+)\.(jpg|jpeg|png|gif)$/i);
                    
                    if (match) {
                        return {
                            file: file,
                            order: parseInt(match[1]),
                            title: match[2],
                            fileName: fileName
                        };
                    } else {
                        // 如果文件名不符合格式，使用默认值
                        return {
                            file: file,
                            order: 0,
                            title: fileName.replace(/\.[^/.]+$/, ""), // 移除扩展名
                            fileName: fileName
                        };
                    }
                }).sort((a, b) => a.order - b.order);
                
                // 显示图片列表
                this.displayImageList(imageData);
                
                // 创建图片浏览器
                this.createBrowser(imageData);
            }
            
            displayImageList(imageData) {
                const imageList = document.getElementById('imageList');
                imageList.innerHTML = '<strong>检测到的图片:</strong>';
                
                imageData.forEach(data => {
                    const item = document.createElement('div');
                    item.className = 'image-item';
                    item.textContent = `序号: ${data.order} | 标题: ${data.title} | 文件: ${data.fileName}`;
                    imageList.appendChild(item);
                });
            }
            
            createBrowser(imageData) {
                // 清空现有内容
                this.track.innerHTML = '';
                this.list = new CircularLinkedList();
                this.nodeElements.clear();
                
                // 创建循环链表
                imageData.forEach(data => {
                    const objectURL = URL.createObjectURL(data.file);
                    this.list.append({
                        title: data.title,
                        src: objectURL,
                        order: data.order
                    });
                });
                
                // 创建DOM节点
                this.createImageNodes();
                // 更新显示
                this.updateDisplay();
                // 创建链表可视化
                this.createLinkedListVisual();
                
                // 启用控制按钮
                document.getElementById('randomSpin').disabled = false;
                document.querySelector('.prev').disabled = false;
                document.querySelector('.next').disabled = false;
            }
            
            createImageNodes() {
                this.track.innerHTML = '';
                
                this.list.getAllNodes().forEach(node => {
                    const nodeElement = document.createElement('div');
                    nodeElement.className = 'image-node';
                    nodeElement.innerHTML = `
                        <img src="${node.data.src}" alt="${node.data.title}">
                        <div class="image-title">${node.data.title}</div>
                    `;
                    
                    this.track.appendChild(nodeElement);
                    node.element = nodeElement;
                    this.nodeElements.set(node, nodeElement);
                });
            }
            
            updateDisplay() {
                if (this.list.length === 0) return;
                
                const current = this.list.getCurrent();
                const prev = current.prev;
                const next = current.next;
                const farPrev = prev.prev;
                const farNext = next.next;
                
                // 重置所有节点
                this.nodeElements.forEach((element, node) => {
                    element.className = 'image-node';
                    element.style.display = 'block';
                });
                
                // 设置位置和样式
                this.setNodePosition(current, 'active', '0%');
                this.setNodePosition(prev, 'left', '-120%');
                this.setNodePosition(next, 'right', '120%');
                this.setNodePosition(farPrev, 'far-left', '-200%');
                this.setNodePosition(farNext, 'far-right', '200%');
                
                // 隐藏其他节点
                this.nodeElements.forEach((element, node) => {
                    if (![current, prev, next, farPrev, farNext].includes(node)) {
                        element.style.display = 'none';
                    }
                });
                
                this.updateStatus();
                this.updateLinkedListVisual();
            }
            
            setNodePosition(node, className, translateX) {
                if (node && node.element) {
                    node.element.className = `image-node ${className}`;
                    node.element.style.transform = `translateX(${translateX})`;
                }
            }
            
            nextImage() {
                if (this.isAnimating || this.list.length === 0) return;
                this.list.next();
                this.updateDisplay();
            }
            
            prevImage() {
                if (this.isAnimating || this.list.length === 0) return;
                this.list.prev();
                this.updateDisplay();
            }
            
            // 带加速度的随机轮动功能
            async randomSpin() {
                if (this.isAnimating || this.list.length === 0) return;
                
                this.isAnimating = true;
                const randomBtn = document.getElementById('randomSpin');
                randomBtn.disabled = true;
                
                // 生成随机步数：5N+1 到 10N
                const minSteps = 5 * this.list.length + 1;
                const maxSteps = 10 * this.list.length;
                const totalSteps = Math.floor(Math.random() * (maxSteps - minSteps + 1)) + minSteps;
                
                // 显示动画信息
                this.showAnimationInfo(`开始随机轮动: ${totalSteps} 步`);
                
                const startTime = Date.now();
                let completedSteps = 0;
                let currentSpeed = this.initialSpeed; // 当前速度（图/秒）
                
                // 计算加速阶段需要的步数（从初始速度加速到最大速度）
                const accelerationSteps = Math.ceil((this.maxSpeed - this.initialSpeed) / this.acceleration * currentSpeed);
                
                // 计算减速阶段需要的步数（从最大速度减速到0）
                const decelerationSteps = Math.ceil(this.maxSpeed / Math.abs(this.deceleration) * this.maxSpeed);
                
                // 计算匀速阶段步数
                const constantSteps = Math.max(0, totalSteps - accelerationSteps - decelerationSteps);
                
                // 动画循环
                const animate = () => {
                    if (completedSteps < totalSteps) {
                        this.list.next();
                        this.updateDisplay();
                        this.highlightCurrentNode();
                        completedSteps++;
                        
                        // 更新当前速度
                        if (completedSteps <= accelerationSteps) {
                            // 加速阶段
                            currentSpeed = Math.min(this.maxSpeed, currentSpeed + this.acceleration / currentSpeed);
                        } else if (completedSteps > totalSteps - decelerationSteps) {
                            // 减速阶段
                            currentSpeed = Math.max(3, currentSpeed + this.deceleration / currentSpeed);
                        }
                        // 匀速阶段保持最大速度
                        
                        // 更新速度显示
                        this.updateSpeedDisplay(currentSpeed);
                        
                        // 计算下一帧的延迟时间（毫秒）
                        const delay = Math.max(50, Math.min(500, 1000 / currentSpeed));
                        
                        // 更新动画信息
                        const elapsed = (Date.now() - startTime) / 1000;
                        const phase = completedSteps <= accelerationSteps ? '加速' : 
                                     completedSteps > totalSteps - decelerationSteps ? '减速' : '匀速';
                        
                        this.showAnimationInfo(
                            `随机轮动中: ${completedSteps}/${totalSteps} 步 | ` +
                            `速度: ${currentSpeed.toFixed(1)} 图/秒 | ` +
                            `阶段: ${phase} | ` +
                            `预计剩余: ${((totalSteps - completedSteps) / currentSpeed).toFixed(1)} 秒`
                        );
                        
                        setTimeout(animate, delay);
                    } else {
                        // 动画完成
                        this.isAnimating = false;
                        randomBtn.disabled = false;
                        this.updateSpeedDisplay(0);
                        this.showAnimationInfo(`随机轮动完成! 总共轮动了 ${totalSteps} 步`);
                        setTimeout(() => {
                            document.getElementById('animationInfo').innerHTML = '';
                        }, 3000);
                    }
                };
                
                animate();
            }
            
            updateSpeedDisplay(speed) {
                const speedFill = document.getElementById('speedFill');
                const percentage = (speed / this.maxSpeed) * 100;
                speedFill.style.width = `${percentage}%`;
                
                // 根据速度改变颜色
                if (speed < 3) {
                    speedFill.style.background = 'linear-gradient(90deg, #4ecdc4, #44a08d)';
                } else if (speed < 7) {
                    speedFill.style.background = 'linear-gradient(90deg, #ffd89b, #19547b)';
                } else {
                    speedFill.style.background = 'linear-gradient(90deg, #ff6b6b, #ee5a24)';
                }
            }
            
            highlightCurrentNode() {
                // 高亮当前链表节点
                document.querySelectorAll('.list-node').forEach(node => {
                    node.classList.remove('animating');
                });
                const currentIndex = this.list.getCurrent().index;
                const currentNode = document.querySelector(`.list-node[data-index="${currentIndex}"]`);
                if (currentNode) {
                    currentNode.classList.add('animating');
                }
            }
            
            showAnimationInfo(message) {
                const infoDiv = document.getElementById('animationInfo');
                infoDiv.innerHTML = `<div class="animation-info">${message}</div>`;
            }
            
            updateStatus() {
                const current = this.list.getCurrent();
                document.getElementById('currentImage').textContent = current.data.title;
                document.getElementById('listLength').textContent = this.list.length;
                
                const pointers = `${current.prev.data.title} ← ${current.data.title} → ${current.next.data.title}`;
                document.getElementById('nodePointers').textContent = pointers;
            }
            
            createLinkedListVisual() {
                const container = document.getElementById('linkedListVisual');
                container.innerHTML = '';
                
                const nodes = this.list.getAllNodes();
                
                if (nodes.length === 0) return;
                
                // 添加循环箭头（开始）
                const startLoop = document.createElement('div');
                startLoop.className = 'loop-arrow';
                startLoop.textContent = '↻';
                container.appendChild(startLoop);
                
                nodes.forEach((node, index) => {
                    // 添加节点
                    const nodeElement = document.createElement('div');
                    nodeElement.className = 'list-node';
                    nodeElement.textContent = node.data.title;
                    nodeElement.dataset.index = index;
                    container.appendChild(nodeElement);
                    
                    // 添加箭头（除了最后一个节点）
                    if (index < nodes.length - 1) {
                        const arrow = document.createElement('div');
                        arrow.className = 'arrow';
                        arrow.textContent = '→';
                        container.appendChild(arrow);
                    }
                });
                
                // 添加循环箭头（结束）
                const endLoop = document.createElement('div');
                endLoop.className = 'loop-arrow';
                endLoop.textContent = '↻';
                container.appendChild(endLoop);
            }
            
            updateLinkedListVisual() {
                const currentIndex = this.list.getCurrent().index;
                document.querySelectorAll('.list-node').forEach((node, index) => {
                    node.classList.toggle('active', index === currentIndex);
                });
            }
            
            bindEvents() {
                document.querySelector('.prev').addEventListener('click', () => this.prevImage());
                document.querySelector('.next').addEventListener('click', () => this.nextImage());
                document.getElementById('randomSpin').addEventListener('click', () => this.randomSpin());
                
                // 初始禁用控制按钮
                document.getElementById('randomSpin').disabled = true;
                document.querySelector('.prev').disabled = true;
                document.querySelector('.next').disabled = true;
                
                // 拖动支持
                this.enableDrag();
            }
            
            enableDrag() {
                let startX = 0;
                let isDragging = false;
                const threshold = 50;
                
                const handleDragStart = (e) => {
                    if (this.isAnimating || this.list.length === 0) return;
                    startX = e.type.includes('mouse') ? e.pageX : e.touches[0].pageX;
                    isDragging = true;
                    this.track.style.cursor = 'grabbing';
                };
                
                const handleDragMove = (e) => {
                    if (!isDragging) return;
                    e.preventDefault();
                };
                
                const handleDragEnd = (e) => {
                    if (!isDragging) return;
                    
                    const endX = e.type.includes('mouse') ? e.pageX : e.changedTouches[0].pageX;
                    const diff = endX - startX;
                    
                    if (Math.abs(diff) > threshold) {
                        if (diff > 0) {
                            this.prevImage();
                        } else {
                            this.nextImage();
                        }
                    }
                    
                    isDragging = false;
                    this.track.style.cursor = 'grab';
                };
                
                // 鼠标事件
                this.track.addEventListener('mousedown', handleDragStart);
                document.addEventListener('mousemove', handleDragMove);
                document.addEventListener('mouseup', handleDragEnd);
                
                // 触摸事件
                this.track.addEventListener('touchstart', handleDragStart);
                document.addEventListener('touchmove', handleDragMove);
                document.addEventListener('touchend', handleDragEnd);
            }
        }

        // 初始化
        document.addEventListener('DOMContentLoaded', function() {
            const browser = new CircularImageBrowser(document.querySelector('.viewer-container'));
            
            // 文件选择处理
            document.getElementById('loadImages').addEventListener('click', function() {
                const fileInput = document.getElementById('fileInput');
                if (fileInput.files.length > 0) {
                    browser.initFromFiles(fileInput.files);
                } else {
                    alert('请先选择图片文件');
                }
            });
        });
    </script>
</body>
</html>